﻿using System;

namespace Netbits.Common.General.CommandLine
{
	/// <summary>
	/// Represent a command-line argument with value of ValueType (int,...)
	/// </summary>
	/// <typeparam name="TValueType">Type of the ValueType</typeparam>
	public sealed class ArgumentValueType<TValueType> : ArgumentBase<TValueType>
	{
		#region Private Variables

		TValueType _MinValue;
		TValueType _MaxValue;

		#endregion

		#region Constructor

		/// <summary>
		/// Create new instance of this class with specified short-name
		/// </summary>
		/// <param name="ShortName_">The short name of this argument</param>
		public ArgumentValueType( string ShortName_ ) : base( ShortName_ )
		{
		}

		#endregion

		#region Public Properties

		/// <summary>
		/// Get or set the minimum value of this argument-value
		/// </summary>
		public TValueType MinValue
		{
			get { return _MinValue; }
			set { _MinValue = value; }
		}

		/// <summary>
		/// Get or set the maximum value of this argument-value
		/// </summary>
		public TValueType MaxValue
		{
			get { return _MaxValue; }
			set { _MaxValue = value; }
		}

		#endregion

		#region Private Functions

		void _HandleBool( string Value_ )
		{
			_Value = Converter.ConvertTo<TValueType>( Value_, _DefaultValue );
		}

		void _HandleUShort( string Value_ )
		{
			ushort value;
			ushort minvalue = Converter.ConvertTo<ushort>( MinValue.ToString() );
			ushort maxvalue = Converter.ConvertTo<ushort>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<ushort>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid unsigned short", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleShort( string Value_ )
		{
			short value;
			short minvalue = Converter.ConvertTo<short>( MinValue.ToString() );
			short maxvalue = Converter.ConvertTo<short>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<short>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid short", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleUInt( string Value_ )
		{
			uint value;
			uint minvalue = Converter.ConvertTo<uint>( MinValue.ToString() );
			uint maxvalue = Converter.ConvertTo<uint>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<uint>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid uint", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleInt( string Value_ )
		{
			int value;
			int minvalue = Converter.ConvertTo<int>( MinValue.ToString() );
			int maxvalue = Converter.ConvertTo<int>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<int>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid int", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleULong( string Value_ )
		{
			ulong value;
			ulong minvalue = Converter.ConvertTo<ulong>( MinValue.ToString() );
			ulong maxvalue = Converter.ConvertTo<ulong>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<ulong>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid unsigned long", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleLong( string Value_ )
		{
			long value;
			long minvalue = Converter.ConvertTo<long>( MinValue.ToString() );
			long maxvalue = Converter.ConvertTo<long>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<long>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid long", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleFloat( string Value_ )
		{
			float value;
			float minvalue = Converter.ConvertTo<float>( MinValue.ToString() );
			float maxvalue = Converter.ConvertTo<float>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<float>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid float", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleDouble( string Value_ )
		{
			double value;
			double minvalue = Converter.ConvertTo<double>( MinValue.ToString() );
			double maxvalue = Converter.ConvertTo<double>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<double>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid double value", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range of {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		void _HandleDecimal( string Value_ )
		{
			decimal value;
			decimal minvalue = Converter.ConvertTo<decimal>( MinValue.ToString() );
			decimal maxvalue = Converter.ConvertTo<decimal>( MaxValue.ToString() );

			try
			{
				value = Converter.ConvertTo<decimal>( Value_ );
			}
			catch
			{
				throw new Exception( string.Format( "{0} not a valid decimal value", Value_ ) );
			}

			if( value < minvalue || value > maxvalue )
				throw new Exception( string.Format( "{0} is not in range from {1} to {2}", Value_, minvalue, maxvalue ) );

			_Value = Converter.ConvertTo<TValueType>( value.ToString() );
		}

		#endregion

		#region Overrides

		/// <summary>
		/// Parse the specified value to this instance
		/// </summary>
		/// <param name="Value_">Value to parse</param>
		public override void Parse( string Value_ )
		{
			Type t = typeof( TValueType );

			if( t == typeof( bool ) )
				_HandleBool( Value_ );
			else if( t == typeof( ushort ) )
				_HandleUShort( Value_ );
			else if( t == typeof( short ) )
				_HandleShort( Value_ );
			else if( t == typeof( uint ) )
				_HandleUInt( Value_ );
			else if( t == typeof( int ) )
				_HandleInt( Value_ );
			else if( t == typeof( ulong ) )
				_HandleULong( Value_ );
			else if( t == typeof( long ) )
				_HandleLong( Value_ );
			else if( t == typeof( float ) )
				_HandleFloat( Value_ );
			else if( t == typeof( double ) )
				_HandleDouble( Value_ );
			else if( t == typeof( decimal ) )
				_HandleDecimal( Value_ );
			else
				throw new Exception( "unknown value type." );

			IsSet = true;
		}

		#endregion
	}
}
